package org.example.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author huangshen
 * @version 0.0.3
 * @description MethodUtil Method工具类
 * @since 2021/12/19 8:23
 */
public class MethodUtils {
    private final Class<?> targetClass;
    private final Iterator<Field> fields;

    private static final String GET = "get";
    private static final String SET = "set";

    public MethodUtils(Class<?> targetClass) {
        this.targetClass = targetClass;
        this.fields = Arrays.asList(targetClass.getDeclaredFields()).iterator();
    }

    /**
     * 获取指定对象中带有指定注解的参数的get方法
     *
     * @param annotationClass 指定注解
     */
    public <E extends Annotation> List<Method> getGetMethodListByAnnotation(Class<E> annotationClass) {
        List<Method> methodList = new LinkedList<>();
        try {
            while (fields.hasNext()) {
                Field field = fields.next();
                E annotation = field.getAnnotation(annotationClass);
                if (!Function.equalsNull(annotation)) {
                    String methodName = GET + StringUtils.toFirstLetterUpperCase(field.getName());
                    methodList.add(targetClass.getMethod(methodName));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return methodList;
    }

    /**
     * 获取指定对象中所有参数的set方法
     *
     * @param annotationClass 指定注解
     */
    public <E extends Annotation> List<Method> getSetMethodListByAnnotation(Class<E> annotationClass) {
        List<Method> methodList = new LinkedList<>();
        Map<String, Class<?>> types = TypeUtils.getParamTypesByAnnotation(targetClass, annotationClass);
        try {
            while (fields.hasNext()) {
                Field field = fields.next();
                if (!Function.equalsNull(field.getAnnotation(annotationClass))) {
                    String methodName = SET + StringUtils.toFirstLetterUpperCase(field.getName());
                    methodList.add(targetClass.getMethod(methodName, types.get(field.getName())));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return methodList;
    }

    /**
     * @param method 执行的方法
     * @param bean   执行的对象
     * @return java.lang.Object 获取的值
     * @author huangshen
     * @demandNum 0
     * @date 2022/1/28
     */
    public static Object getValue(Method method, Object bean) {
        Object invoke = null;
        try {
            invoke = method.invoke(bean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Function.equalsNull(invoke) ? "" : invoke;
    }

    /**
     * 通过参数名集合返回参数名对应的get方法
     *
     * @param fieldNameList 参数名集合
     * @return method方法
     */
    public List<Method> getGetMethodListByFiledNameList(List<String> fieldNameList) {
        List<Method> methodList = new LinkedList<>();
        Iterator<String> strings = fieldNameList.listIterator();
        try {
            while (strings.hasNext()) {
                String fieldName = strings.next();
                methodList.add(targetClass.getMethod(GET + StringUtils.underline2Camel(fieldName, false)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return methodList;
    }

    /**
     * 获取指定对象中所有参数的set方法并执行
     *
     * @param entityClass 目标class
     * @param paramMap    map参数
     * @return Object
     */
    public static Object mapValueSetBean(Map<String, Object> paramMap, Class<?> entityClass, Map<String, Class<?>> types) {
        try {
            Object beanObj = entityClass.newInstance();
            if (paramMap == null) {
                return beanObj;
            }
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                String setMethodName = SET + StringUtils.toFirstLetterUpperCase(entry.getKey());
                Method method = entityClass.getMethod(setMethodName, types.get(entry.getKey()));
                method.invoke(beanObj, entry.getValue());
            }
            return beanObj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


}
